// Copyright 2004-2021 Castle Project - http://www.castleproject.org/
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Castle.DynamicProxy.Tests
{
	using System.Linq;
	using System.Reflection;

	using Castle.DynamicProxy.Internal;

	using NUnit.Framework;

	[TestFixture]
	public class TypeUtilTestCase
	{
		[Test]
		public void GetAllInstanceMethods_GetsPublicAndNonPublicMethods()
		{
			MethodInfo[] methods =
				typeof(object).GetAllInstanceMethods();
			MethodInfo[] realMethods =
				typeof(object).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
			CollectionAssert.AreEquivalent(realMethods, methods);
		}

		// The test above suggests that `TypeUtil.GetAllInstanceMethods` and `Type.GetMethods`
		// can be used interchangeably, but this is not always the case. See the test(s) below and
		// `GenericInterfaceProxyTestCase.GetAllInstanceMethodsIsStable` for cases where the two methods
		// may produce different results.

#if NET5_0_OR_GREATER

		[Test]
		public void GetAllInstanceMethods_NoDuplicatesForMethodWithCovariantReturnType()
		{
			MethodInfo[] methods =
				typeof(Derived).GetAllInstanceMethods();
			MethodInfo[] realMethods =
				typeof(Derived).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
			CollectionAssert.AreNotEquivalent(realMethods, methods);
			CollectionAssert.IsSubsetOf(subset: methods, superset: realMethods);
			Assert.AreEqual(2, realMethods.Where(m => m.Name == nameof(Derived.Method)).Count());
			Assert.AreEqual(1, methods.Where(m => m.Name == nameof(Derived.Method)).Count());
		}

		public abstract class Base
		{
			public abstract Base Method();
		}

		public abstract class Derived : Base
		{
			public override abstract Derived Method();
		}

#endif
	}
}
